package com.lmx.persistence.service.common;

import java.io.Serializable;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.beans.PropertyValue;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.transaction.annotation.Transactional;

import com.google.common.collect.Lists;
import com.lmx.common.context.ActionContextHolder;
import com.lmx.common.util.CommonUtil;
import com.lmx.persistence.IOperations;
import com.lmx.repoDomain.tmodel.Tenant;

@Transactional
public abstract class AbstractService<T extends Serializable> implements IOperations<T> {
    private Log logger = LogFactory.getLog(this.getClass());

    // read - one

    @Override
    @Transactional(readOnly = true)
    public T findOne(final long id) {
        return getDao().findOne(id);
    }

    // read - all

    @Override
    @Transactional(readOnly = true)
    public List<T> findAll() {
        return Lists.newArrayList(getDao().findAll());
    }

    @Override
    public Page<T> findPaginated(final int page, final int size) {
        return getDao().findAll(new PageRequest(page, size));
    }

    // write

    @Override
    public T create( T entity) {
        entity = (T)setCreateTime(entity);
        return getDao().save(entity);
    }
    @Override
    public T createEntity( T entity) {
        return getDao().save(entity);
    }
    
    /**
     * 设置创建时间
     * @param source
     * @return
     */
    public static Object setCreateTime (Object source) {
        final BeanWrapper src = new BeanWrapperImpl(source);
        java.beans.PropertyDescriptor[] pds = src.getPropertyDescriptors();
        Set<String> emptyNames = new HashSet<String>();
        for(java.beans.PropertyDescriptor pd : pds) {
            Object srcValue = src.getPropertyValue(pd.getName());
            if("createTime".equals(pd.getName()) && srcValue == null){
                src.setPropertyValue(new PropertyValue("createTime",CommonUtil.getCurrTimes()));
                source = src.getWrappedInstance();
            }
            if("updateTime".equals(pd.getName()) && srcValue == null){
                src.setPropertyValue(new PropertyValue("updateTime",CommonUtil.getCurrTimes()));
                source = src.getWrappedInstance();
            }
            if("createDateTime".equals(pd.getName()) && srcValue == null){
                src.setPropertyValue(new PropertyValue("createDateTime",CommonUtil.getCurrTimes()));
                source = src.getWrappedInstance();
            }
            if("lastUpdateDateTime".equals(pd.getName()) && srcValue == null){
                src.setPropertyValue(new PropertyValue("lastUpdateDateTime",CommonUtil.getCurrTimes()));
                source = src.getWrappedInstance();
            }
            if("delStatus".equals(pd.getName()) && srcValue == null){
                src.setPropertyValue(new PropertyValue("delStatus",0));
                source = src.getWrappedInstance();
            }
            if(!"com.lmx.repoDomain.tmodel.TenantPrivilege".equals(source.getClass().getName())){
                if("tenant".equals(pd.getName()) && srcValue == null){
                	Long tenantId=ActionContextHolder.getContext().getTenantId();
                	if(tenantId!=null){
                    	Tenant tenant=new Tenant();
                    	tenant.setId(tenantId);
                        src.setPropertyValue(new PropertyValue("tenant",tenant));
                        source = src.getWrappedInstance();
                	}
                }
            }
            if(!"com.lmx.repoDomain.tmodel.User".equals(source.getClass().getName())){
                if("createUser".equals(pd.getName()) && srcValue == null){
                        src.setPropertyValue(new PropertyValue("createUser",ActionContextHolder.getContext().getUser()));
                        source = src.getWrappedInstance();
                }
            }
        }
        return source;
    }

    @Override
    @Cacheable
    public T update(T entity) {
        entity = (T)setUpdateTime(entity);
/*        T saveEntity = getDao().findOne(((BaseDataEntity)entity).getId());
        CommonUtil.copyNonNullProperties(entity, saveEntity);
        return getDao().save(saveEntity);*/
        return getDao().save(entity);
    }

    /**
     * 设置更新时间
     * @param source
     * @return
     */
    public static Object setUpdateTime (Object source) {
        final BeanWrapper src = new BeanWrapperImpl(source);
        java.beans.PropertyDescriptor[] pds = src.getPropertyDescriptors();
        Set<String> emptyNames = new HashSet<String>();
        for(java.beans.PropertyDescriptor pd : pds) {
            Object srcValue = src.getPropertyValue(pd.getName());
            if("updateTime".equals(pd.getName()) /*&& srcValue == null*/){
                src.setPropertyValue(new PropertyValue("updateTime",CommonUtil.getCurrTimes()));
                source = src.getWrappedInstance();
            }
            if("lastUpdateDateTime".equals(pd.getName())){
                src.setPropertyValue(new PropertyValue("lastUpdateDateTime",CommonUtil.getCurrTimes()));
                source = src.getWrappedInstance();
            }
            if("tenant".equals(pd.getName()) && srcValue == null){
            	Long tenantId=ActionContextHolder.getContext().getTenantId();
            	if(tenantId!=null){
                	Tenant tenant=new Tenant();
                	tenant.setId(tenantId);
                    src.setPropertyValue(new PropertyValue("tenant",tenant));
                    source = src.getWrappedInstance();
            	}
            }
        }
        return source;
    }


    @Override
    public void delete(final T entity) {
        getDao().delete(entity);
    }

    @Override
    public void deleteById(final long entityId) {
        getDao().delete(entityId);
    }

    protected abstract PagingAndSortingRepository<T, Long> getDao();

}
